﻿using System;

namespace Hotfix
{

    internal enum EnumParserState
    {
        ParserSize,// 解析长度(头)
        parserBody //  解析身体
    }


    /// <summary>
    /// 一个数据包结构 | 长度 2字节 | 类型 2字节 | 数据 |
    /// </summary>
    public struct Packet
    {
        #region 字段
        public byte[] Bytes { get; set; }

        public int Length { get; set; }

        #endregion

        #region 构造
        public Packet(int length)
        {
            this.Length = length;
            Bytes = new byte[length];
        }

        public Packet(byte[] butes)
        {
            this.Length = butes.Length;
            this.Bytes = butes;
        }
        #endregion

    }

    /// <summary>
    /// 包解析器
    /// </summary>
    public class PacketParser
    {
        #region 字段

        private RingBuffer ringBuffer;
        /// <summary>
        /// 是否完成
        /// </summary>
        private bool isOk;
        private ushort packetSize;
        private EnumParserState parserState;
        private Packet packet = new Packet(1024 * 8);

        #endregion

        #region 构造
        public PacketParser(RingBuffer ringBuffer)
        {
            this.ringBuffer = ringBuffer;
        }
        #endregion

        #region 实例方法

        /// <summary>
        /// 解析
        /// </summary>
        /// <returns></returns>
        public bool Parser()
        {
            if (isOk) return true;

            bool finish = false; // 是否完成

            while (!finish)
            {
                switch (parserState)
                {
                    case EnumParserState.ParserSize:

                        if (ringBuffer.Count < 2)
                            finish = true;
                        else
                        {
                            ringBuffer.RecvSource(packet.Bytes, 2);
                            this.packetSize = BitConverter.ToUInt16(packet.Bytes, 0);
                            if (packetSize > 60000)
                                throw new Exception("packet too large，size:" + packetSize);

                            this.parserState = EnumParserState.parserBody;
                        }

                        break;
                    case EnumParserState.parserBody:

                        if (ringBuffer.Count < packetSize)
                            finish = true;
                        else
                        {
                            ringBuffer.RecvSource(packet.Bytes, packetSize);
                            packet.Length = packetSize;
                            isOk = true;
                            this.parserState = EnumParserState.ParserSize;
                            finish = true;
                        }
                        break;
                }
            }
            return isOk;
        }

        public Packet GetPacket()
        {
            isOk = false;
            return packet;
        }

        #endregion
    }
}
